# -*- coding: utf-8 -*-
"""
@ Created on 2024-06-14 12:23
---------
@summary: 通用CRUD抽象基类
---------
@author: Lsaiah
"""

from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Optional, List, Dict, Any, Type
from fastapi import Depends, Query
from core.auth import AuthHandler
from core.response import ResponseModel, ListResponseModel
from constant import *
from log import logger

# 定义泛型类型
T = TypeVar('T')  # 模型类型
CreateSchema = TypeVar('CreateSchema')  # 创建请求模型
UpdateSchema = TypeVar('UpdateSchema')  # 更新请求模型

auth_handler = AuthHandler()


class AbstractCRUD(ABC, Generic[T, CreateSchema, UpdateSchema]):
    """通用CRUD抽象基类"""
    
    def __init__(self, model: Type[T], crud_class, create_schema: Type[CreateSchema], update_schema: Type[UpdateSchema]):
        """
        初始化CRUD基类
        
        Args:
            model: TortoiseORM模型类
            crud_class: CRUD操作类
            create_schema: 创建请求模型类
            update_schema: 更新请求模型类
        """
        self.model = model
        self.crud_class = crud_class
        self.create_schema = create_schema
        self.update_schema = update_schema
        self.table_name = getattr(model._meta, 'table', model.__name__.lower())
    
    async def page(
        self,
        page: int = Query(1, ge=1, description="页码"),
        size: int = Query(10, ge=1, le=100, description="每页数量"),
        search: Optional[str] = Query(None, description="搜索关键词"),
        **filters
    ) -> ListResponseModel:
        """分页查询"""
        try:
            skip = (page - 1) * size
            
            # 获取数据列表
            items = await self.crud_class.get_list(
                skip=skip, 
                limit=size, 
                search=search, 
                **filters
            )
            
            # 统计总数
            total = await self.crud_class.count_list(
                search=search, 
                **filters
            )
            
            # 转换为字典列表
            data_list = []
            for item in items:
                data_list.append(await self._model_to_dict(item))
            
            return ListResponseModel.success(
                list_data=data_list,
                page=page,
                size=size,
                total=total
            )
            
        except Exception as e:
            logger.error(f"分页查询失败: {str(e)}")
            from datetime import datetime
            return ListResponseModel(
                code=CODE_ERROR,
                message=f"分页查询失败",
                data=None,
                timestamp=datetime.now().isoformat()
            )
    
    async def get(
        self,
        id: int = Query(..., description="记录ID"),
        current_user = Depends(auth_handler.get_current_active_user())
    ) -> ResponseModel:
        """获取详情"""
        try:
            item = await self.crud_class.get_by_id(id)
            if not item:
                return ResponseModel.not_found(f"{self.table_name}不存在")
            
            return ResponseModel.success(data=await self._model_to_dict(item))
            
        except Exception as e:
            logger.error(f"获取详情失败: {str(e)}")
            return ResponseModel.error(
                message=f"获取详情失败",
                code=CODE_ERROR
            )
    
    async def create(
        self,
        data: CreateSchema,
        current_user = Depends(auth_handler.get_current_active_user())
    ) -> ResponseModel:
        """创建记录"""
        try:
            # 转换为字典
            create_data = data.dict(exclude_unset=True)
            
            # 创建记录
            item = await self.crud_class.create(create_data)
            
            return ResponseModel.success(
                data={"id": item.id},
                message=MESSAGE_DATA_CREATE_SUCCESS,
                code=CODE_DATA_CREATE_SUCCESS
            )
            
        except Exception as e:
            logger.error(f"创建记录失败: {str(e)}")
            return ResponseModel.error(
                message=f"创建记录失败",
                code=CODE_ERROR
            )
    
    async def update(
        self,
        data: UpdateSchema,
        current_user = Depends(auth_handler.get_current_active_user())
    ) -> ResponseModel:
        """更新记录"""
        try:
            # 检查记录是否存在
            item = await self.crud_class.get_by_id(data.id)
            if not item:
                return ResponseModel.not_found(f"{self.table_name}不存在")
            
            # 转换为字典，排除None值
            update_data = data.dict(exclude_unset=True, exclude_none=True)
            update_data.pop('id', None)  # 移除id字段
            
            # 更新记录
            updated_item = await self.crud_class.update(data.id, update_data)
            if not updated_item:
                return ResponseModel.error(
                    message=f"更新{self.table_name}失败",
                    code=CODE_ERROR
                )
            
            return ResponseModel.success(
                data={"id": updated_item.id},
                message=MESSAGE_DATA_UPDATE_SUCCESS,
                code=CODE_DATA_UPDATE_SUCCESS
            )
            
        except Exception as e:
            logger.error(f"更新记录失败: {str(e)}")
            return ResponseModel.error(
                message=f"更新记录失败",
                code=CODE_ERROR
            )
    
    async def delete(
        self,
        id: int = Query(..., description="记录ID"),
        current_user = Depends(auth_handler.get_current_active_user())
    ) -> ResponseModel:
        """删除记录"""
        try:
            # 检查记录是否存在
            item = await self.crud_class.get_by_id(id)
            if not item:
                return ResponseModel.not_found(f"{self.table_name}不存在")
            
            # 删除记录
            success = await self.crud_class.delete(id)
            if not success:
                return ResponseModel.error(
                    message=f"删除{self.table_name}失败",
                    code=CODE_ERROR
                )
            
            return ResponseModel.success(
                message=MESSAGE_DATA_DELETE_SUCCESS,
                code=CODE_DATA_DELETE_SUCCESS
            )
            
        except Exception as e:
            logger.error(f"删除记录失败: {str(e)}")
            return ResponseModel.error(
                message=f"删除记录失败",
                code=CODE_ERROR
            )
    
    async def _model_to_dict(self, model_instance: T) -> Dict[str, Any]:
        """将模型实例转换为字典"""
        try:
            # 使用TortoiseORM的内置序列化
            from tortoise.contrib.pydantic import pydantic_model_creator
            pydantic_model = pydantic_model_creator(type(model_instance))
            serialized = await pydantic_model.from_tortoise_orm(model_instance)
            return serialized.dict()
        except Exception as e:
            logger.error(f"序列化模型失败: {str(e)}")
            # 备用方法：手动转换基本字段
            result = {}
            try:
                for field_name in ['id', 'created_at', 'updated_at']:
                    if hasattr(model_instance, field_name):
                        value = getattr(model_instance, field_name)
                        if hasattr(value, 'isoformat'):
                            result[field_name] = value.isoformat() if value else None
                        else:
                            result[field_name] = value
                
                # 添加其他基本字段
                for field_name in model_instance._meta.fields_map.keys():
                    if field_name not in result and not field_name.endswith('_set'):
                        try:
                            value = getattr(model_instance, field_name)
                            if hasattr(value, 'isoformat'):
                                result[field_name] = value.isoformat() if value else None
                            elif hasattr(value, 'id'):
                                result[field_name] = value.id if value else None
                            else:
                                result[field_name] = value
                        except:
                            continue
            except Exception as e2:
                logger.error(f"备用序列化也失败: {str(e2)}")
                result = {"id": getattr(model_instance, 'id', None)}
            
            return result
    
    @abstractmethod
    def get_router(self):
        """获取路由，子类需要实现"""
        pass
